#!/usr/bin/python
# -*- coding: utf-8 -*-

from BeautifulSoup import *
import re
import tool_tree as tt
from array import array

def split_generique(chaine,inter,motif,mode_end):
  s,e = inter
  patt = re.finditer(motif,chaine[s:e],re.UNICODE)
  l = []
  end = s
  l = [(match.start()+s, match.end()+s) for match in patt]
  l.append((end,e))
  return l

def split_sentence(s,i) :
  motif = '(.+?(\. ))'
  l = split_generique(s,i,motif,False)
  return l

def split_virgulot(s,i) :
  motif = '(.+?([,;] ))'
  l = split_generique(s,i,motif,True)
  return l

def split_word(s,i) :
  motif = '(.+?(\s))'
  l = split_generique(s,i,motif,True)
  return l

def rec_split(s, i, list_seg, segmenter_i):
  start,end = i
  if segmenter_i == len(list_seg) :
    return [i, []]
  segmenter = list_seg[segmenter_i]
  res = [i, []]
  for inter in segmenter(s,i) :
    sl = rec_split(s, inter, list_seg, segmenter_i+1)
    res[1].append(sl)
  return res

def get_nb_elt_depth(tree, depth) :
  if depth == 0 :
    return len(tree[1])
  s = 0
  for son in tree[1] :
    s += get_nb_elt_depth(son, depth-1)
  return s

def str_indented_tree(s,a) :
  return str_indented_tree_aux(s,a,0)

def str_indented_tree_aux(s,a,p) :
  i,sons = a
  out = "%s[%s]%s"%("   "*p,s[i[0]:i[1]].encode('utf-8'),"\n")
  for a_sons in sons :
     out += str_indented_tree_aux(s,a_sons,p+1)
  return out

def forest_height_singleton_root(forest) :
  list_c = []
  for tree in forest :
    hr = tt.get_singleton_height_root(tree)
    list_c.append(hr)
  return list_c

def get_caracteristics_par(forest) :
  list_c = []
  for tree in forest :
    hr = tt.get_singleton_height_root(tree)
    if hr >= 2 :
      list_c.append('T')
    elif hr == 1 :
      list_c.append('t')
    else :
      list_c.append('p')
  return list_c

def get_sections(list_par, list_carac, id_start) :
  s = ''.join(list_carac[id_start:])
  l = re.finditer('T+[^T]{1,}|[^T]+|T+',s)
  list_sections = []
  for m in l :
    len_sec = m.end() - m.start()
    true_start = m.start() + id_start
    sec = Section(true_start, len_sec, list_par, list_carac)
    list_sections.append(sec)
  return list_sections

def get_forest_document(bs) :
  f = []
  list_p = []
  for p in bs.body :
    if type(p) == Tag and p.name == 'p':
      try :
        s = p.string.strip(' \n\t\r')
      except :
        continue
      seg_list = [split_sentence,split_virgulot,split_word]
      u = rec_split(s, (0, len(s)), seg_list, 0)
      f.append(u)
      list_p.append(s)
  return f, list_p

class Section :
  def __init__(self, id_par_start, len_sec, list_par, list_carac) :
    self.id_start = id_par_start
    self.len_sec = len_sec
    self.list_par = list_par
    self.list_carac = list_carac
    self.ini_content()
    self.ini_title()

  def get_title(self) :
    return self.title

  def ini_title(self) :
    self.title = []
    for i in xrange(self.id_start, self.id_start+self.len_sec) :
      if self.list_carac[i] != 'T' :
        break
      self.title.append(i)

  def get_content(self) :
    return self.content

  def ini_content(self) :
    self.content = []
    for i in xrange(self.id_start, self.id_start+self.len_sec) :
      if self.list_carac[i] == 'T' :
        continue
      self.content.append(i)

  def __str__(self) :
    id_par_title = self.get_title()
    id_par_content = self.get_content()
    l = ['*'*10]
    for i in id_par_title :
      l.append('   %s'%(self.list_par[i]))
    for i in id_par_content :
      l.append('%s'%(self.list_par[i]))
    res = "\n".join(l)
    return res.encode('utf-8')

class Title_doc(Section) :
  def ini_title(self) :
    self.title = array('i',range(self.id_start, self.id_start + self.len_sec))

  def ini_content(self) :
    self.content = array('i',range(self.id_start, self.id_start + self.len_sec))

  def __str__(self) :
    id_par = self.get_title()
    l = [    unicode('┌───────────','utf-8')]
    border = unicode('│', 'utf-8')
    for i in id_par :
      l.append('%s %s'%(border,self.list_par[i]))
    l.append(unicode('└───────────','utf-8'))
    res = "\n".join(l)
    return res.encode('utf-8')


def get_tgt_granularity_aux(tree, cpt) :
  if len(tree[1]) == 1 :
    return get_tgt_granularity_aux(tree[1][0], cpt + 1)
  return cpt

def get_tgt_granularity(document) :
  forest = document.forest
  ls = len(document.list_sections)
  if ls == 0 :
    return 2#"0Sec"
  elif ls == 1 :
    list_par = document.list_sections[0].get_content()
    lp = len(list_par)
    if lp == 0 :
      return 4#"1Sec, 0Par"
    elif lp == 1 :
      n = get_tgt_granularity_aux(forest[list_par[0]],0)
      return 3+n#"1Sec, 1Par, level : %s"%(n)
    return 1#"1Sec, nPar"
  return 0#"nSec"

def extreme_document(document, granularity) :
  if granularity == 0 :
    #first and last section
    start = start_document_0(document)
    end = end_document_0(document)
    return start,end
  elif granularity == 1 :
    #first and last paragraph
    start = start_document_1(document)
    end = end_document_1(document)
    return start,end
  elif granularity == 2 :
    #first and last paragraph of the title
    start, end = extreme_document_2(document)
    return start,end
  elif granularity >= 3 :
    #first and last element at level %s of the paragraph
    level = granularity-3
    start,end = extreme_document_3(document, level)
    return start,end
  return "unknown granularity"

def extreme_document_3(document, level) :
  f = document.forest
  start = tt.get_nXinY_path_forest(f,0,2,level+1)
  end   = tt.get_nXinY_path_forest_rev(f,0,2,level+1)
  end.sort()
  return start, end

def extreme_document_2(document) :
  f = document.forest
  start = tt.get_nXinY_path_forest(f,0,2,1)
  end   = tt.get_nXinY_path_forest_rev(f,0,2,1)
  end.reverse()
  return start,end
  res = []
  flag = False
  forest = document.forest
  for id_par in document.title.content :
    res.append(id_par)
    if flag or len(forest[id_par][1]) > 1 :
      break
    flag = True
  start = [[i] for i in res]

  res = []
  flag = False
  for id_par in document.title.content[::-1] :
    res.append(id_par)
    if flag or len(forest[id_par][1]) > 1 :
      break
    flag = True
  res.sort()
  end = [[i] for i in res]

  return start, end

def start_document_0(document) :
  res = document.title.content
  flag = False
  for section in document.list_sections :
    res.extend(section.title)
    res.extend(section.content)
    if flag or len(section.content) > 1 :
      break
    flag = True    
  return [[i] for i in res]

def end_document_0(document) :
  res = []
  flag = False
  for section in document.list_sections[::-1] :
    res.extend(section.title)
    res.extend(section.content)
    if flag or len(section.content) > 1 :
      break
    flag = True    
  res.sort()
  return [[i] for i in res]

def start_document_1(document) :
  res = []
  res.extend(document.title.content)
  res.extend(document.list_sections[0].title)
  forest = document.forest
  flag = False
  for id_par in document.list_sections[0].content :
    res.append(id_par)
    if flag or len(forest[id_par][1]) > 1 :
      break
    flag = True
  return [[i] for i in res]

def end_document_1(document) :
  res = []
  flag = False
  forest = document.forest
  for id_par in document.list_sections[0].content[::-1] :
    res.append(id_par)
    if flag or len(forest[id_par][1]) > 1 :
      break
    flag = True
  return [[i] for i in res]

class Document :
  def __init__(self,path) :
    self.path = path
    self.ini_content()
    self.ini_tree_document()
    self.ini_carac_paragraph()
    self.ini_title_doc()
    self.ini_sections()

  def ini_content(self) :
    f = open(self.path)
    self.content = unicode(f.read(),'utf-8')
    f.close()

  def ini_tree_document(self) :
    bs = BeautifulSoup(self.content)
    self.forest,self.list_paragraph = get_forest_document(bs)

  def ini_carac_paragraph(self) :
    l = []
    for tree in self.forest :
      hr = tt.get_singleton_height_root(tree)
      if hr >= 2    : v='T'
      elif hr == 1  : v = 't'
      else          : v = 'p'
      l.append(v)
    self.list_carac = l
    self.string_carac = "".join(l)

  def ini_title_doc(self) :
    m = re.search('[^tT]*[tT]+', self.string_carac)
    if m :
      self.title = Title_doc(0, m.end(), self.list_paragraph, self.list_carac)
    else :
      l = len(self.string_carac)
      self.title = Title_doc(0, l, self.list_paragraph, self.list_carac)

  def ini_sections(self) :
    first_start = self.title.len_sec
    l = re.finditer('T+[^T]{1,}|[^T]+|T+',self.string_carac[first_start:])
    self.list_sections = []
    for m in l :
      len_sec = m.end() - m.start()
      start = m.start() + first_start
      sec = Section(start, len_sec, self.list_paragraph, self.list_carac)
      self.list_sections.append(sec)
